#include "buck_pwm_control.h"
#include <stdio.h>              // C/C++库：标准输入输出。printf();

#include "ohos_init.h"          // OH公共基础库：SYS_RUN();
#include "hi_gpio.h"            // 海思hi3861SDK：hi_gpio_init();hi_gpio_set_dir();HI_GPIO_DIR_OUT
#include "hi_io.h"              // 海思hi3861SDK：hi_io_set_func();HI_IO_NAME_GPIO_9;HI_IO_FUNC_GPIO_9_PWM0_OUT
#include "hi_pwm.h"             // 海思hi3861SDK：hi_pwm_init();hi_pwm_set_clock();hi_pwm_start();HI_PWM_PORT_PWM0;PWM_CLK_XTAL;hi_u16;

// #include "iot_gpio.h"           // IOT硬件子系统：IoTGpioInit();IOT_GPIO_DIR_OUT
#include "iot_pwm.h"            // IOT硬件子系统：IoTPwmInit()

// ADS1X15
#include "ADS1X15.h"

// SSD1306
#include "ssd1306.h"

float CurrentMax = 30.0000;         // 最大充电电流A

float VoltageMax = 30.0000;         // 最大充电电压V
float InVoltagePrev = 0.0000;       // 保存前一步输入电压

float InPower = 0.0000;             // 输入功率W
float InPowerPrev = 0.0000;         // 保存前一步输入功率W
int BuckDuty = 0;


void PWM_Entry(){

    hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_PWM0_OUT);      //设置GPIO引脚复用
    hi_pwm_init(HI_PWM_PORT_PWM0);
    // hi_pwm_set_clock(PWM_CLK_XTAL);     // 设置时钟源为晶体时钟（Hi3861的晶体时钟为40MHz，默认时钟源160MHz）


    hi_pwm_port port = HI_PWM_PORT_PWM0;
    if(0){  //如果1，那么使用海思hi3861SDK接口。
        while (1){
            hi_u16 duty = 1;
            for (hi_u16 freq = 1; freq < 10; freq += 1)
            {
                /**
                 * @param port:输出PWM的通道号，非GPIO号。
                 * @param duty:一个频率周期内高电平数(1-65535,默认750)。
                 * @param freq：将时钟源分成几份，最终输出频率=时钟源/freq(1-65535,默认1500)。
                 * @note duty必须小于freq，否则start无效。
                 * @note 输出频率最小为160000KHz/65535=2.441KHz
                 */
                hi_pwm_start(port, duty, freq);
                printf("freq:%d.\n",freq);
                sleep(5);
            }
        } 
    }else{  //如果0，使用IOT硬件子系统接口，start参数不太一样。
        while (1){
            unsigned short duty = 50;   //占空比50%
            for (unsigned int freq = 10000000; freq < 4294967295; freq += 10000000)//初始10MHz。每次加10MHz
            {
                /**
                 * @param port:输出PWM的通道号，非GPIO号。
                 * @param duty:占空比(1-99,直接设置占空比)。
                 * @param freq：设置输出频率，单位Hz。
                 * @note freq理论最大设置4294967295≈4294MKz，但是Hi3861最大160MHz
                 */
                IoTPwmStart(port, duty, freq);//160MHz,实测2.5KHz；40MHz,实测40MHz；30MHz,实测32MHz；也可以测错了，改天再试。
                printf("freq:%d.\n",freq);
                sleep(5);
            }
        } 
    }

   
}

// SYS_RUN(PWM_Entry);


void PwmInit(void){
    printf("PwmInit().\n");
    hi_gpio_set_dir(HI_IO_NAME_GPIO_10, HI_GPIO_DIR_OUT);                //Buck电路开启关闭


    hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_PWM0_OUT);      //设置GPIO引脚复用，提供buck电路PWM
    hi_pwm_init(HI_PWM_PORT_PWM0);
}

void BuckPwmControl(bool state,int duty){
    if (state)
    {
        // printf("BuckPwm true,duty%d.\n",duty);
        hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_10,HI_GPIO_VALUE1);
        IoTPwmStart(HI_PWM_PORT_PWM0, duty, 39000);//输出频率39KHz
    }else{
        // printf("BuckPwm false,duty%d.\n",duty);
        hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_10,HI_GPIO_VALUE0);
        IoTPwmStart(HI_PWM_PORT_PWM0, duty, 39000);
    }

    char strDst[3] = {0};
    ssd1306_SetCursor(60, 10);
    ssd1306_DrawString("duty:", Font_7x10, White);
    sprintf_s(strDst,3,"%d",duty);
    ssd1306_DrawString(strDst, Font_7x10, White);
}


static hi_u8 constrain_hi_u8(hi_u8 amt, hi_u8 low, hi_u8 high){        //限幅函数
    return ((amt)<(low)?(low):((amt)>(high)?(high):(amt)));
}
/**
 * @brief 预测Buck占空比
 * 
 */
void PredictiveBuckDuty(OperatingData *operatingData){
    BuckDuty = (operatingData->outvoltage/operatingData->involtage)*100;
    BuckDuty = constrain_hi_u8(BuckDuty,1,99);
    printf("初始化Buck降压电压占空比：%d。\n",BuckDuty);

}

void MpptAlgorithm(OperatingData *operatingData){
    // printf("3输入电压:%f,2输出电压:%f,1输入电流:%f,0输出电流:%f,温度电阻:%f\n",operatingData->involtage,operatingData->outvoltage,operatingData->incurrent,operatingData->outcurrent,operatingData->temp);
    // printf("2输出电压:%f\n",operatingData->outvoltage);
    // printf("1输入电流:%f\n",operatingData->incurrent);
    // printf("0电压:%f\n",operatingData->outcurrent);



    InPower = operatingData->involtage * operatingData->incurrent;    //太阳能输入功率W
    // printf("当前Buck降压电压占空比:%d。P:%f,PP:%f,InV:%f,InVP:%f\n",BuckDuty,InPower,InPowerPrev,operatingData->involtage,InVoltagePrev);
    if (NULL != operatingData)
    {
        if (operatingData->incurrent > CurrentMax)             // 如果超过最大充电电流
        {
            BuckDuty--;
            printf("超过最大充电电流");
        }else if (operatingData->outvoltage > VoltageMax)
        {
            BuckDuty--;
            printf("超过最大充电电压");
        }else
        {
            if (InPower > InPowerPrev && operatingData->involtage > InVoltagePrev)     // 如果 ↑P ↑V
            {
                BuckDuty--;
                printf("↑P ↑V");
            }else if (InPower > InPowerPrev && operatingData->involtage < InVoltagePrev)   // 如果 ↑P ↓V
            {
                BuckDuty++;
                printf("↑P ↓V");
            }else if (InPower < InPowerPrev && operatingData->involtage > InVoltagePrev)       //↓P ↑V
            {
                BuckDuty++;
                printf("↓P ↑V");
            }else if (InPower < InPowerPrev && operatingData->involtage < InVoltagePrev)       //↓P ↓V
            {
                BuckDuty--;
                printf("↓P ↓V");
            }else if (operatingData->outvoltage < VoltageMax)            // 如果超过最大充电电压
            {
                BuckDuty++;
                printf("以达到目标充电电压。");
            }
            InPowerPrev = InPower;
            InVoltagePrev =  operatingData->involtage;     // 保存此次输入电压

        }
        BuckDuty = constrain_hi_u8(BuckDuty,51,99);
        BuckPwmControl(true,BuckDuty);              // 设置Buck电路占空比
    }
  


    


    // if(currentOutput > currentCharging){PWM--;}                                      // 电流高了，减小占空比。Current Is Above → Decrease Duty Cycle
    // else if(voltageOutput > voltageBatteryMax){PWM--;}                               // 电压高了，减小占空比。Voltage Is Above → Decrease Duty Cycle   
    // else{                                                                          //MPPT ALGORITHM
    // if(powerInput>powerInputPrev && voltageInput>voltageInputPrev)     {PWM--;}  //  输入↑P 输入↑V ; →MPP  //D--
    // else if(powerInput>powerInputPrev && voltageInput<voltageInputPrev){PWM++;}  //  输入↑P 输入↓V ; MPP←  //D++
    // else if(powerInput<powerInputPrev && voltageInput>voltageInputPrev){PWM++;}  //  输入↓P 输入↑V ; MPP→  //D++
    // else if(powerInput<powerInputPrev && voltageInput<voltageInputPrev){PWM--;}  //  输入↓P 输入↓V ; ←MPP  //D--
    // else if(voltageOutput<voltageBatteryMax)                           {PWM++;}  //  MP MV ; MPP Reached - 
    // powerInputPrev   = powerInput;                                               //Store Previous Recorded Power 存储先前记录的功率
    // voltageInputPrev = voltageInput;                                             //Store Previous Recorded Voltage 存储先前记录的电压 
    // }   
    // PWM_Modulation();  
}

 
// //*********** Structure Definition ********//
// typedef struct {
// 	double  Ipv;
// 	double  Vpv;
// 	double  DeltaPmin;
// 	double  MaxVolt;
// 	double  MinVolt;
// 	double  Stepsize;
// 	double  VmppOut;
// 	double  DeltaP;
// 	double  PanelPower;
// 	double  PanelPower_Prev;
// 	int mppt_enable;
// 	int mppt_first;
// } MPPT_PNO_F;
 
// //*********** Structure Init Function ****//
// void MPPT_PNO_F_init(MPPT_PNO_F *v)
// {
// 	v->Ipv=0;					// Report_Data->involtage
// 	v->Vpv=0;
// 	v->DeltaPmin=(0.00001);
// 	v->MaxVolt=(0.9);
// 	v->MinVolt=0;
// 	v->Stepsize=(0.002);
// 	v->VmppOut=0;
// 	v->DeltaP=0;
// 	v->PanelPower=0;
// 	v->PanelPower_Prev=0;
// 	v->mppt_enable=1;
// 	v->mppt_first=1;
// }
 
// //*********** Function Definition ********//
// void MPPT_PNO_F_FUNC(MPPT_PNO_F *v)
// {
// 	if (v->mppt_enable == 1)
// 	{
// 		if (v->mppt_first == 1)
// 		{
// 			v->VmppOut = v->Vpv - (0.02);
// 			v->mppt_first = 0;
// 			v->PanelPower_Prev = v->PanelPower;
// 		}
// 		else
// 		{
// 			v->PanelPower = (v->Vpv * v->Ipv);
// 			v->DeltaP = v->PanelPower - v->PanelPower_Prev;		// 求 △P = 输出功率 - 上一步输出功率
// 			if (v->DeltaP > v->DeltaPmin)						// 如果 △P > 0.00001，即输出功率变大了
// 			{
// 				v->VmppOut = v->Vpv + v->Stepsize;					// Buck电压 = 输出电压 + 步长
// 			}
// 			else												// 如果输出功率变小了
// 			{
// 				if (v->DeltaP < -v->DeltaPmin)						// 如果 △P < -0.00001 为负
// 				{
// 					v->Stepsize = -v->Stepsize;							// 步长改为负
// 					v->VmppOut = v->Vpv + v->Stepsize;					// Buck电压 = 输出电压 - 步长
// 				}
// 			}
// 			v->PanelPower_Prev = v->PanelPower;					// 保存当前功率
// 		}
// 		if(v->VmppOut < v->MinVolt) v->VmppOut = v->MinVolt;
// 		if(v->VmppOut > v->MaxVolt) v->VmppOut = v->MaxVolt;
// 	}
// }
 
//*********** Structure Definition ********//
// typedef struct {
// 	float32  Ipv;
// 	float32  Vpv;           // 当前电压
// 	float32  IpvH;
// 	float32  IpvL;
// 	float32  VpvH;
// 	float32  VpvL;
// 	float32  MaxVolt;       // 最大电压
// 	float32  MinVolt;       // 最小电压
// 	float32  Stepsize;      // 步长
// 	float32  VmppOut;       // *【buck电路输出的电压】*
// 	// internal variables
// 	float32  Cond;          // 电导率
// 	float32  IncCond;
// 	float32  DeltaV;        // 变化电压
// 	float32  DeltaI;        // 变化电流
// 	float32  VpvOld;        // 上一步电压
// 	float32  IpvOld;
// 	float32  StepFirst;     // 第一步长
// 	int16 mppt_enable;      // 启动mppt
// 	int16 mppt_first;       // mppt首次启动时
// } MPPT_INCC_F;
 
// typedef MPPT_INCC_F *mppt_incc_handle;
 
 
// //*********** Structure Init Function ****//
// void MPPT_INCC_F_init(MPPT_INCC_F *v)
// {
// 	v->Ipv=0;
// 	v->Vpv=0;
// 	v->IpvH=(1.65);
// 	v->IpvL=0;
// 	v->VpvH=0;
// 	v->VpvL=0;
// 	v->MaxVolt=0;
// 	v->MinVolt=0;
// 	v->Stepsize=0;
// 	v->VmppOut=0;
// 	v->Cond=0;
// 	v->IncCond=0;
// 	v->DeltaV=0;
// 	v->DeltaI=0;
// 	v->VpvOld=0;
// 	v->IpvOld=0;
// 	v->StepFirst=(0.02);
// 	v->mppt_enable=1;
// 	v->mppt_first=1;
// }
 
// //*********** Function Definition ********//
// void MPPT_INCC_F_FUNC(MPPT_INCC_F *v)
// {
// 	if (v->mppt_enable==1)
// 	{	/*MPPT mode enable*/
// 		if (v->mppt_first == 1)
// 		{
// 			v->VmppOut= v->Vpv - v->StepFirst;  // 当前电压 - 首步步长0.02
// 	    	v->VpvOld=v->Vpv;                   // 上一步电压
// 	    	v->IpvOld=v->Ipv;                   // 上一步电流
// 			v->mppt_first=0;                    // mppt首次启动完成
// 		}
// 		else
// 		{
// 			v->DeltaV = v->Vpv-v->VpvOld ; 				/* PV电压变化 */
// 	    	v->DeltaI = v->Ipv-v->IpvOld ; 				/* PV电流变化 */
// //	   		if(v->DeltaV <v->VpvH && v->DeltaV >-v->VpvL )  /* Tolerence limits PV Voaltge Variation 容限PV电压变化 */
// //	    	v->DeltaV= 0;
// //	   		if(v->DeltaI <v->IpvH && v->DeltaI >-v->IpvL )  /* Tolerence limits PV current Variation 容差限制PV电流变化 */
// //	    	v->DeltaI = 0;
// 	    	if(v->DeltaV == 0)    						/* DeltaV=0 */
// 			{
// 				if(v->DeltaI !=0 )    					/* dI=0 operating at MPP 在MPP操作*/
// 				{
// 					if ( v->DeltaI > 0 )  				/* climbing towards MPP 爬向MPP*/
// 					{v->VmppOut = v->Vpv + v->Stepsize;}		/* Increment Vref 增量Vref*/
// 					else
// 					{v->VmppOut = v->Vpv - v->Stepsize;} 		/* Decrement Vref 减量Vref*/
// 				}
// 			}
// 	    	else
// 			{
// 	    	 	v->Cond = v->Ipv*__einvf32(v->Vpv);					/*Cond =-(v->Ipv<<10)/v->Vpv; 求导*/
// 	    	 	v->IncCond = v->DeltaI*__einvf32(v->DeltaV);			/*IncCond =(DeltaI<<10)/DeltaV;*/
// 	       		if (v->IncCond != v->Cond)				/* Operating at MPP 在MPP操作*/
// 				{
// 					if (v->IncCond > (-v->Cond))			/* left of MPP */
// 					{
// 					v->VmppOut = v->Vpv + v->Stepsize;			/* change Vref */
// 					}
// 					else								/* Right of MPP */
// 					{
// 					v->VmppOut = v->Vpv - v->Stepsize;			/* change Vref */
// 					}
// 	        	}
// 			}
// 			v->VpvOld = v->Vpv;
// 			v->IpvOld = v->Ipv;
// 		}
// 	}
// }